package com.onlyxiahui.extend.query.hibernate;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

//import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Query;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.springframework.orm.hibernate5.HibernateCallback;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

import com.onlyxiahui.extend.query.hibernate.handler.JpaHandler;
import com.onlyxiahui.extend.query.hibernate.handler.result.ResultType;
import com.onlyxiahui.extend.query.hibernate.handler.xml.QueryItem;
import com.onlyxiahui.extend.query.hibernate.syntax.data.QueryHandleData;
import com.onlyxiahui.extend.query.hibernate.syntax.data.QueryHandleUtil;
import com.onlyxiahui.extend.query.hibernate.syntax.util.DeleteHqlUtil;
import com.onlyxiahui.extend.query.hibernate.syntax.util.QueryHqlUtil;
import com.onlyxiahui.extend.query.hibernate.syntax.util.UpdateHqlUtil;
import com.onlyxiahui.extend.query.hibernate.util.DbReflectUtil;
import com.onlyxiahui.extend.query.hibernate.util.QueryUtil;
import com.onlyxiahui.extend.query.page.QueryPage;

/**
 *
 * Date 2018-12-29 11:27:36<br>
 * Description
 *
 * @author XiaHui<br>
 * @since 1.0.0
 */
public abstract class AbstractDAO extends HibernateDaoSupport {

	protected QueryContext queryContext;

	public void setQueryContext(QueryContext queryContext) {
		this.queryContext = queryContext;
	}

	public JpaHandler getHandler() {
		return queryContext.getJpaHandler();
	}

	/**
	 *
	 * Date 2018-12-29 11:27:52<br>
	 * Description 根据主键id获取实体对象
	 *
	 * @author XiaHui<br>
	 * @param <T>
	 * @param entityClass
	 * @param id
	 * @return
	 * @since 1.0.0
	 */
	public <T> T get(Class<T> entityClass, Serializable id) {
		return this.getHibernateTemplate().get(entityClass, id);
	}

	/**
	 *
	 * Date 2018-12-29 11:28:08<br>
	 * Description 新增数据
	 *
	 * @author XiaHui<br>
	 * @param <T>
	 * @param t
	 * @return
	 * @since 1.0.0
	 */
	public <T> Serializable save(T t) {
		return this.getHibernateTemplate().save(t);
	}

	/**
	 * 修改对象 Date 2018-12-29 11:28:20<br>
	 * Description
	 *
	 * @author XiaHui<br>
	 * @param <T>
	 * @param t
	 * @since 1.0.0
	 */
	public <T> void update(T t) {
		this.getHibernateTemplate().update(t);
	}

	public <T> int updateSelective(T t) {
		int count = 0;
		String name = t.getClass().getName();

		Field field = DbReflectUtil.getField(t.getClass(), Object.class, Id.class);
		if (null != field) {
			// Column c = field.getAnnotation(Column.class);
			// String id = (null == c || c.name() == null) ? field.getName() : c.name();
			String idName = field.getName();
			QueryWrapper qw = QueryUtil.getQueryWrapper(t);
			String hql = UpdateHqlUtil.getUpdateHql(name, idName, qw);
			count = this.executeHql(hql, qw);
		} else {
			throw new RuntimeException("找不到" + name + "实体的主键");
		}
		return count;

//		Entity e = t.getClass().getAnnotation(Entity.class);
//		
//		if(null==e) {
//			Table t=t.getClass().getAnnotation(Table.);
//		}

//		this.getHibernateTemplate().executeWithNativeSession(session -> {
//			SessionImpl s = (SessionImpl) session;
//			EntityPersister ep = s.getEntityPersister(t.getClass().getName(), t);
//			EntityMetamodel em = ep.getEntityMetamodel();
//			boolean changed = false;
//			if (!em.isDynamicUpdate()) {
//				ReflectUtil.setValueByFieldName(em, "dynamicUpdate", true);
//				changed = true;
//			}
//			session.update(t);
//			if (changed) {
//				ReflectUtil.setValueByFieldName(em, "dynamicUpdate", false);
//			}
//			return null;
//		});
		// this.getHibernateTemplate().merge(t);
	}

	public <T> int updateSelective(Class<T> entityClass, Map<String, Object> map) {
		QueryWrapper qw = QueryUtil.getQueryWrapper(map);
		return updateSelective(qw);
	}

	public <T> int updateSelective(Class<T> entityClass, QueryWrapper qw) {
		int count = 0;
		if (null != entityClass) {
			String entityName = entityClass.getName();
			Field field = DbReflectUtil.getField(entityClass, Object.class, Id.class);
			if (null != field) {
//				Column c = field.getAnnotation(Column.class);
//				String idName = (null == c || c.name() == null) ? field.getName() : c.name();
				String idName = field.getName();
				String hql = UpdateHqlUtil.getUpdateHql(entityName, idName, qw);
				count = this.executeHql(hql, qw);
			} else {
				throw new RuntimeException("找不到" + entityName + "实体的主键");
			}
		} else {
			throw new RuntimeException("实体类不能为空");
		}
		return count;
	}

	public <T> int updateSelective(Class<T> entityClass, QueryWrapper qw, List<String> keyNames) {
		int count = 0;
		if (null != entityClass) {
			String entityName = entityClass.getName();
			String hql = UpdateHqlUtil.getUpdateHql(entityName, keyNames, qw);
			count = this.executeHql(hql, qw);
		} else {
			throw new RuntimeException("实体类不能为空");
		}
		return count;
	}

	public <T> int updateSelective(Class<T> entityClass, Object data, List<String> keyNames) {
		QueryWrapper qw = QueryUtil.getQueryWrapper(data);
		return updateSelective(entityClass, qw, keyNames);
	}

	public <T> int updateSelective(Class<T> entityClass, QueryWrapper qw, String... keyNames) {
		List<String> keyNameList = new ArrayList<>();
		if (null != keyNames) {
			for (String key : keyNames) {
				keyNameList.add(key);
			}
		}
		return updateSelective(entityClass, qw, keyNameList);
	}

	public <T> int updateSelective(Class<T> entityClass, Object data, String... keyNames) {
		QueryWrapper qw = QueryUtil.getQueryWrapper(data);
		return updateSelective(entityClass, qw, keyNames);
	}

	/**
	 *
	 * Date 2018-12-29 11:28:35<br>
	 * Description 根据有无主键执行新增或者修改
	 *
	 * @author XiaHui<br>
	 * @param <T>
	 * @param t
	 * @since 1.0.0
	 */
	public <T> void saveOrUpdate(T t) {
		this.getHibernateTemplate().saveOrUpdate(t);
	}

	/**
	 *
	 * Date 2018-12-29 11:28:44<br>
	 * Description 删除数据
	 *
	 * @author XiaHui<br>
	 * @param <T>
	 * @param t
	 * @since 1.0.0
	 */
	public <T> void delete(T t) {
		this.getHibernateTemplate().delete(t);
	}

	/**
	 * 根据类名删除数据
	 *
	 * @param entityName
	 * @param entity
	 */
	public void delete(String entityName, Object entity) {
		this.getHibernateTemplate().delete(entityName, entity);
	}

	/**
	 * 批量删除实体数据
	 *
	 * @param entities
	 */
	public void deleteAll(Collection<?> entities) {
		this.getHibernateTemplate().deleteAll(entities);
	}

	/**
	 * 根据类和id删除对象
	 *
	 * @param entityClass
	 * @param id
	 */
	public int deleteById(Class<?> entityClass, Serializable id) {
		int count = 0;
		if (null != entityClass) {
			String entityName = entityClass.getName();
			Field field = DbReflectUtil.getField(entityClass, Object.class, Id.class);
			if (null != field) {
//				Column c = field.getAnnotation(Column.class);
//				String idName = (null == c || c.name() == null) ? field.getName() : c.name();
				String idName = field.getName();
				QueryWrapper qw = new QueryWrapper();
				qw.addParameter(idName, id);
				String hql = DeleteHqlUtil.getDeleteHql(entityName, qw);
				count = this.executeHql(hql, qw);
			} else {
				throw new RuntimeException("找不到" + entityName + "实体的主键");
			}
		} else {
			throw new RuntimeException("实体类不能为空");
		}
		return count;
	}

	public int deleteByCondition(Class<?> entityClass, QueryWrapper qw) {
		int count = 0;
		if (null != entityClass) {
			String entityName = entityClass.getName();
			if (null != qw && null != qw.getParameterMap() && !qw.getParameterMap().isEmpty()) {
				String hql = DeleteHqlUtil.getDeleteHql(entityName, qw);
				count = this.executeHql(hql, qw);
			} else {
				throw new RuntimeException("条件不能为空");
			}
		} else {
			throw new RuntimeException("实体类不能为空");
		}
		return count;
	}

	public int deleteByCondition(Class<?> entityClass, Object data) {
		QueryWrapper qw = QueryUtil.getQueryWrapper(data);
		return deleteByCondition(entityClass, qw);
	}

	public <T> void saveList(final List<T> list) {
		if (null != list) {
			this.getHibernateTemplate().execute(new HibernateCallback<List<T>>() {
				@Override
				public List<T> doInHibernate(Session session) throws HibernateException {
					int batch = 0;
					for (Object o : list) {
						session.save(o);
						batch++;
						if (batch == 50) {// 每50条批量提交一次。
							session.flush();
							session.clear();
							batch = 0;
						}
					}
					return list;
				}
			});
		}
	}

	public <T> void updateList(final List<T> list) {
		if (null != list) {
			this.getHibernateTemplate().execute(new HibernateCallback<List<T>>() {
				@Override
				public List<T> doInHibernate(Session session) throws HibernateException {
					int batch = 0;
					for (Object o : list) {
						session.update(o);
						batch++;
						if (batch == 50) {// 每50条批量提交一次。
							session.flush();
							session.clear();
							batch = 0;
						}
					}
					return list;
				}
			});
		}
	}

	/**
	 * 批量根据有无主键执行新增或者修改
	 *
	 * @param <T>
	 * @param list
	 */
	public <T> void saveOrUpdateList(final List<T> list) {
		if (null != list) {
			this.getHibernateTemplate().execute(new HibernateCallback<List<T>>() {
				@Override
				public List<T> doInHibernate(Session session) throws HibernateException {
					int batch = 0;
					for (Object o : list) {
						session.saveOrUpdate(o);
						batch++;
						if (batch == 50) {// 每50条批量提交一次。
							session.flush();
							session.clear();
							batch = 0;
						}
					}
					return list;
				}
			});
		}
	}

	public List<?> find(String hql, Object... values) {
		return this.getHibernateTemplate().execute(new HibernateCallback<List<?>>() {
			@Override
			public List<?> doInHibernate(Session session) throws HibernateException {
				Query query = session.createQuery(hql);

				if (null != values) {
					int l = values.length;
					for (int i = 0; i < l; i++) {
						query.setParameter(i, values[i]);
					}
				}
				return query.getResultList();
			}
		});
	}

	/************************/

	public <T> T get(Class<T> entityClass, QueryWrapper queryWrapper) {
		if (null == queryWrapper ||
				null == queryWrapper.getParameterMap() ||
				queryWrapper.getParameterMap().isEmpty()) {
			return null;
		} else {
			queryWrapper.setPage(1, 1);
			List<T> list = list(entityClass, queryWrapper, (QueryHandleData) null);
			if (list.isEmpty()) {
				return null;
			} else {
				return list.get(0);
			}
		}
	}

	public <T> T get(Class<T> entityClass, Object query) {
		if (null == query) {
			return null;
		} else {
			QueryHandleData queryHandleData = QueryHandleUtil.get(query);
			QueryWrapper queryWrapper = QueryUtil.getQueryWrapperType(query, queryHandleData.getOptions());
			queryWrapper.setPage(1, 1);
			List<T> list = list(entityClass, queryWrapper, queryHandleData);
			if (list.isEmpty()) {
				return null;
			} else {
				return list.get(0);
			}
		}
	}

	public <T> List<T> list(Class<T> entityClass, Object query) {
		QueryHandleData queryHandleData = QueryHandleUtil.get(query);
		QueryWrapper queryWrapper = QueryUtil.getQueryWrapperType(query, queryHandleData.getOptions());
		return list(entityClass, queryWrapper, queryHandleData);
	}

	public <T> List<T> list(Class<T> entityClass, QueryWrapper queryWrapper) {
		return list(entityClass, queryWrapper, (QueryHandleData) null);
	}

	public <T> List<T> list(Class<T> entityClass, Object query, QueryPage page) {
		QueryHandleData queryHandleData = QueryHandleUtil.get(query);
		QueryWrapper queryWrapper = QueryUtil.getQueryWrapperType(query, queryHandleData.getOptions());
		queryWrapper.setPage(page);
		return list(entityClass, queryWrapper, queryHandleData);
	}

	public <T> List<T> list(Class<T> entityClass, QueryWrapper queryWrapper, QueryHandleData queryHandleData) {
		List<T> list = new ArrayList<>();
		if (null != entityClass) {
			list = (List<T>) this.queryListByQueryHandleData(entityClass, queryHandleData, queryWrapper, entityClass);
		}
		return list;
	}

	/**
	 * SQL start
	 * **************************************************************************************
	 */
	/**
	 * 执行sql语句
	 *
	 * @param sql
	 * @return
	 */
	public int executeSql(String sql) {
		return executeSql(sql, null);
	}

	/**
	 * 执行带传入数据的sql
	 *
	 * @param sql
	 * @param queryWrapper
	 * @return
	 */
	public int executeSql(String sql, QueryWrapper queryWrapper) {
		return this.getHibernateTemplate().execute(new HibernateCallback<Integer>() {
			@Override
			public Integer doInHibernate(Session session) throws HibernateException {
				return getHandler().updateBySql(session, sql, queryWrapper);
			}
		});
	}

	/**
	 * 执行sql查询，返回单个对象
	 *
	 * @param <T>
	 * @param sql
	 * @param queryWrapper
	 * @param resultClass
	 * @param returnTypeList
	 * @return
	 */
	public <T> T queryObjectBySql(String sql, QueryWrapper queryWrapper, Class<T> resultClass, List<ResultType> returnTypeList) {
		return this.getHibernateTemplate().execute(new HibernateCallback<T>() {
			@Override
			public T doInHibernate(Session session) throws HibernateException {
				return getHandler().queryObjectBySql(session, sql, queryWrapper, resultClass, returnTypeList);
			}
		});
	}

	/**
	 * 执行sql返回list对象
	 *
	 * @param sql
	 * @param queryWrapper
	 * @param resultClass
	 * @param returnTypeList
	 * @return
	 */
	public <T> List<T> queryListBySql(String sql, QueryWrapper queryWrapper, Class<T> resultClass, List<ResultType> returnTypeList) {

		return this.getHibernateTemplate().execute(new HibernateCallback<List<T>>() {
			@Override
			public List<T> doInHibernate(Session session) throws HibernateException {
				return getHandler().queryListBySql(session, sql, queryWrapper, resultClass, returnTypeList);
			}
		});
	}

	/**
	 * SQL end
	 * **************************************************************************************
	 */
	/**
	 * HQL start
	 * **************************************************************************************
	 */
	/**
	 * 执行sql语句
	 *
	 * @param hql
	 * @return
	 */
	public int executeHql(String hql) {
		return executeHql(hql, null);
	}

	/**
	 * 执行带传入数据的hql
	 *
	 * @param hql
	 * @param queryWrapper
	 * @return
	 */
	public int executeHql(String hql, QueryWrapper queryWrapper) {
		return this.getHibernateTemplate().execute(new HibernateCallback<Integer>() {
			@Override
			public Integer doInHibernate(Session session) throws HibernateException {
				return getHandler().updateByHql(session, hql, queryWrapper);
			}
		});
	}

	/**
	 * 执行sql查询，返回单个对象
	 *
	 * @param <T>
	 * @param hql
	 * @param queryWrapper
	 * @param resultClass
	 * @return
	 */
	public <T> T queryObjectByHql(String hql, QueryWrapper queryWrapper, Class<T> resultClass) {
		return this.getHibernateTemplate().execute(new HibernateCallback<T>() {
			@Override
			public T doInHibernate(Session session) throws HibernateException {
				return getHandler().queryObjectByHql(session, hql, queryWrapper, resultClass);
			}
		});
	}

	/**
	 * 执行sql返回list对象
	 *
	 * @param <T>
	 * @param hql
	 * @param queryWrapper
	 * @param resultClass
	 * @return
	 */
	public <T> List<T> queryListByHql(String hql, QueryWrapper queryWrapper, Class<T> resultClass) {

		return this.getHibernateTemplate().execute(new HibernateCallback<List<T>>() {
			@Override
			public List<T> doInHibernate(Session session) throws HibernateException {
				return getHandler().queryListByHql(session, hql, queryWrapper, resultClass);
			}
		});
	}

	public <T> List<T> queryListByQueryHandleData(Class<T> entityClass, QueryHandleData queryHandleData, QueryWrapper queryWrapper, Class<T> resultClass) {

		return this.getHibernateTemplate().execute(new HibernateCallback<List<T>>() {
			@SuppressWarnings("unchecked")
			@Override
			public List<T> doInHibernate(Session session) throws HibernateException {
				List<T> list = new ArrayList<>();
				if (null != entityClass) {
					String entityName = entityClass.getName();
					String countHql = QueryHqlUtil.getQueryHql(entityName, queryWrapper, queryHandleData, true);
					String listHql = QueryHqlUtil.getQueryHql(entityName, queryWrapper, queryHandleData, false);
					getHandler().queryResultCountByHql(session, countHql, queryWrapper);
					list = (List<T>) getHandler().queryResultListByHql(session, listHql, queryWrapper, resultClass);
				}
				return list;
			}
		});
	}

	/**
	 * HQL end
	 * **************************************************************************************
	 */
	/**
	 * 根据xml配置的name执行
	 *
	 * @param name
	 * @param queryWrapper
	 * @return
	 */
	public int executeByName(String name, QueryWrapper queryWrapper) {
		String text = queryContext.getQueryContent(name, queryWrapper);
		boolean isHql = isHqlByName(name);
		if (isHql) {
			return executeHql(text, queryWrapper);
		} else {
			return executeSql(text, queryWrapper);
		}
	}

	/**
	 *
	 * Date 2018-12-29 11:26:56<br>
	 * Description 根据xml配置的name执行sql，返回单个对象
	 *
	 * @author XiaHui<br>
	 * @param <T>
	 * @param name
	 * @param queryWrapper
	 * @param resultClass
	 * @return
	 * @since 1.0.0
	 */
	public <T> T queryObjectByName(String name, QueryWrapper queryWrapper, Class<T> resultClass) {
		QueryItem queryItem = queryContext.getQueryItem(name);
		String text = queryContext.getQueryContent(name, queryWrapper);
		List<ResultType> resultTypeList = queryItem.getResultTypeList();

		boolean isHql = isHql(queryItem);
		if (isHql) {
			return queryObjectByHql(text, queryWrapper, resultClass);
		} else {
			return queryObjectBySql(text, queryWrapper, resultClass, resultTypeList);
		}
	}

	/**
	 *
	 * Date 2018-12-29 11:26:33<br>
	 * Description 根据xml配置的name执行sql，返回list对象
	 *
	 * @author XiaHui<br>
	 * @param <T>
	 * @param name
	 * @param queryWrapper
	 * @param resultClass
	 * @return
	 * @since 1.0.0
	 */
	public <T> List<T> queryListByName(String name, QueryWrapper queryWrapper, Class<T> resultClass) {
		QueryItem queryItem = queryContext.getQueryItem(name);
		String text = queryContext.getQueryContent(name, queryWrapper);
		List<ResultType> resultTypeList = queryItem.getResultTypeList();
		boolean isHql = isHql(queryItem);
		if (isHql) {
			return queryListByHql(text, queryWrapper, resultClass);
		} else {
			return queryListBySql(text, queryWrapper, resultClass, resultTypeList);
		}
	}

	boolean isHqlByName(String name) {
		QueryItem queryItem = queryContext.getQueryItem(name);
		return isHql(queryItem);
	}

	boolean isHql(QueryItem queryItem) {
		String type = (null != queryItem) ? queryItem.getType() : "";
		return null != type && type.toLowerCase().equals("hql");
	}
}
